/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { assert, beforeAll, describe, expect, test } from 'vitest';
import { CHECK_MODE, testCaseCheck } from './common/testCommon';
import path from 'path';
import { SymbolUsageCheck } from '../../../src/checker/security/SymbolUsageCheck';
import { Rule } from '../../../src/Index';
import { CheckEntry } from '../../../src/utils/common/CheckEntry';

let projectPath: string = '';
let checkEntry: CheckEntry;

beforeAll(async () => {
  projectPath = path.resolve('./test/unittest/sample/SymbolUsage');
  const targetFilePath = path.join(projectPath, 'ets', 'Target.ets');
  const rule: Rule = new Rule('');
  rule.option = [
    {
      "selector": "namespace",
      "filePath": targetFilePath,
      "namespace": ["MySpace"],  // 找namespace使用处
      "class": "",
      "function": "",
      "property": ""
    },
    {
      "selector": "namespace",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],  // 找ns下namespace使用处
      "class": "",
      "function": "",
      "property": ""
    },
    {
      "selector": "class",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "ClassTarget",  // 找类使用处
      "function": "",
      "property": ""
    },
    {
      "selector": "class",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],
      "class": "ClassTarget",  // 找ns下类使用处
      "function": "",
      "property": ""
    },
    {
      "selector": "class",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "InterfaceTarget",  // 找接口使用处
      "function": "",
      "property": ""
    },
    {
      "selector": "class",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],
      "class": "InterfaceTarget",  // 找ns下接口使用处
      "function": "",
      "property": ""
    },
    {
      "selector": "class",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "EnumTarget",  // 找枚举使用处
      "function": "",
      "property": ""
    },
    {
      "selector": "class",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],
      "class": "EnumTarget",  // 找ns下枚举使用处
      "function": "",
      "property": ""
    },
    {
      "selector": "function",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "ClassTarget",
      "function": "methodStatic",  // 找类静态成员方法使用处
      "property": ""
    },
    {
      "selector": "function",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],
      "class": "ClassTarget",
      "function": "methodStatic",  // 找ns下类静态成员方法使用处
      "property": ""
    },
    {
      "selector": "function",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "ClassTarget",
      "function": "methodTarget",  // 找类实例成员方法使用处
      "property": ""
    },
    {
      "selector": "function",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],
      "class": "ClassTarget",
      "function": "methodTarget",  // 找类实例成员方法使用处
      "property": ""
    },
    {
      "selector": "function",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "",
      "function": "funcTarget",  // 找全局方法使用处
      "property": ""
    },
    {
      "selector": "function",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],
      "class": "",
      "function": "funcTarget",  // 找ns下全局方法使用处
      "property": ""
    },
    {
      "selector": "property",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "ClassTarget",
      "function": "",
      "property": "fieldTarget",  // 找类实例属性使用处
    },
    {
      "selector": "property",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],
      "class": "ClassTarget",
      "function": "",
      "property": "fieldTarget"  // 找ns下类实例属性使用处
    },
    {
      "selector": "property",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "ClassTarget",
      "function": "",
      "property": "fieldStatic",  // 找类静态属性使用处
    },
    {
      "selector": "property",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],
      "class": "ClassTarget",
      "function": "",
      "property": "fieldStatic",  // 找ns下类静态属性使用处
    },
    {
      "selector": "type",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "",
      "function": "",
      "property": "",
      "type": "TypeTarget",  // 找type使用处
    },
    {
      "selector": "type",
      "filePath": targetFilePath,
      "namespace": ["MySpace", "InnerSpace"],
      "class": "",
      "function": "",
      "property": "",
      "type": "TypeTarget",  // 找ns下type使用处
    },
    {
      "selector": "class",
      "filePath": targetFilePath,
      "namespace": [],
      "class": "StructTarget",  // 找sturct使用处
      "function": "",
      "property": "",
      "type": ""
    },
    {
      "selector": "type",
      "filePath": targetFilePath,
      "namespace": ['NSTest'],
      "class": "",
      "function": "",
      "property": "",
      "type": "Constructor"  // 找泛型方法别名
    },
    {
      "selector": "function",
      "filePath": targetFilePath,
      "namespace": ['NSTest'],
      "class": "",
      "function": "testFunc",
      "property": "",
      "type": ""
    },
  ];
  checkEntry = await testCaseCheck(projectPath, rule, CHECK_MODE.PROJECT2CHECK, SymbolUsageCheck);
})

describe('SymbolUsageTest', () => {
  test('SymbolUsageTest_001', () => {
    const detectFile: string = path.join(projectPath, 'ets', 'FindStructTest.ets');
    const expectReportList = [
      '21%5%16%', '25%5%16%',  // 使用目标struct
    ];
    const detectFileReports = checkEntry.projectCheck.issues.filter(issue => issue.defect.mergeKey.startsWith(detectFile));
    assert.equal(detectFileReports.length, expectReportList.length, 'The number of reported line is different from the expected number of line.');
    detectFileReports.forEach((issue, index) => {
      assert.include(issue.defect.fixKey, expectReportList[index]);
    });
  });
})